/* This file declares the functions used to get and put characters to the UART (tty) */

#ifndef UART_H
#define UART_H

#define UNUSED 0
#define PRINTING 1
#define READING 2

#include "process_management.h"
#include "malta.h"
#include "fifo_queue.h"
#include "error_codes.h"

#define INTERNAL_QUEUE_LENGTH 10


/* internal queue type declaration. It's a FIFO queue that is used to implement some functionalities (like backspace) */

typedef struct{
  char queue[INTERNAL_QUEUE_LENGTH];
  int32_t count;
  int32_t in;
  int32_t out;
}internal_queue_t;

/* functions to manipulate the internal queue */

/* puts the character c in the internal queue. Returns 0 if the queue is full, 1 otherwise. */
int32_t internal_queue_put(char c);

/* gets the first character in the internal queue, copies it in c and removes it from the queue. Returns 0 if the queue is empty, 1 otherwise. */
int32_t internal_queue_get(char* c);

/* resets the internal queue */
void reset_internal_queue();

/* functions to manipulate the UART */

/* configures the UART */
void configure_uart();

/* cleans the uart's receiving buffer of any data that might be left in it */
void clean_uart();

/* sets the global variables with the correct values to print data */
void set_printing_mode(const char* data);

/* sets the global variables with the correct values to get input from the user and store it into data (up to length-1 characters) */
void set_reading_mode(char* data, int32_t length);

/* function called by the exception handler in case of tty0 originating exceptions */
void uart_handler();

/* pcb tries to become the UART's owner. If it is not possible, it is placed into the UART's FIFO queue . Returns SUCCESS if pcb is now the owner of the device, IN_UART_QUEUE if it is blocked in the queue and FAILURE in case of fatal error.*/
int32_t get_uart(PCB* pcb);

/* releases the UART and the new owner is the first process blocked in the queue. Both the old and new owners are waken up by this function. Returns SUCCESS in case of success, FAILURE if it is impossible to wake the old owner up or the new owner.  */
int32_t release_uart();

/* removes PCB from the fifo queye */
int32_t remove_uart_queue(PCB* pcb);

/* tries to get a character from the UART. Waits for one if none is available. Stops when the character entered is \r or when in_buffer_length - 1 characters have been read, whichever comes first. */ 
void read();

/* prints a character from out_buffer and sets the device to interrupt when it is done printing (only if there are remaining characters to print) */ 
void print();

/* ends the current use of the device and returns an error code that the owner */
int32_t end_of_io();

/* ends the use of the device by its current owner by waking it up. It also release the device and put the return code in the PCB. */
int32_t end_of_printing(int32_t code);

/* this function is exactly like end_of_printing except that it adds also a \0 character at the end of input */
int32_t end_of_reading(int32_t code);

#endif
